package com.xy6.dpdemo.book.delegate;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 委托模式示例。也是java动态代理机制
 * <pre>
 * 委托模式是软件设计模式中的一项基本技巧。
 * 在委托模式中，有两个对象参与处理同一个请求，接受请求的对象将请求委托给另一个对象来处理。
 * 委托模式是一项基本模式，许多其他的模式，如状态模式、策略模式、访问者模式 本质上是在更特殊的场合采用了委托模式。
 * 委托模式使得我们可以用聚合来替代继承。
 * </pre>
 * 
 * @author zhang
 * @since 2018-04-18
 */
public class Delegator implements InvocationHandler {

	// 原始对象
	protected Object obj_orgin = null;
	// 代理对象
	protected Object obj_proxy = null;

	public Delegator(){
	}
	
	public Delegator(Object orgin){
		this.createProxy(orgin);
	}
	
	protected Object createProxy(Object orgin){
		obj_orgin = orgin;
		// 下面语句中orgin.getClass().getClassLoader()为加载器
		// orgin.getClass().getInterfaces()为接口集，orgin类实现的所有接口，不包括父级的父级
		// 委托
		obj_proxy = Proxy.newProxyInstance(orgin.getClass().getClassLoader(), orgin.getClass().getInterfaces(), this);
		return obj_proxy;
	}
	
	protected Object invokeSuper(Method method, Object[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException{
		System.out.println("invoke super");
		// 当代理对象调用真实对象的方法时，其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
		return method.invoke(obj_orgin, args);
	}
	
	@Override
	public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
		// 下面实现的方法是当委托的类调用toString()方法时，操作其他方法而不是该类默认的toString()，这个类的其他方法则不会。
		// 缺省实现：委托为obj_orgin完成对应的操作
		if(method.getName().equals("toString")){
			// 对其做额外处理
			return this.invokeSuper(method, args) + "$Proxy";
		} else {
			// 注意，调用原始对象的方法，而不是代理的(obj==obj_proxy)
			return this.invokeSuper(method, args);
		}
	}

}
